﻿using Super_Management_Mayhem.Content.Spritesheet;
using Super_Management_Mayhem.Content.Spritesheet.Player;
using Super_Management_Mayhem.Control;
using Super_Management_Mayhem.Screens;
using Super_Management_Mayhem.Screens.Menu;
using Super_Management_Mayhem.Screens.Menu.SelectPlayers;
using Super_Management_Mayhem.Screens.Menu.SelectTeams;
using Super_Management_Mayhem.Screens.Playing;
using Super_Management_Mayhem.Screens.Playing.GameMode;
using Super_Management_Mayhem.Screens.Playing.UI;
using Super_Management_Mayhem.Screens.Result;
using System;
using System.Collections.Generic;
using System.Linq;
using Transformable_Engine_v2.Engine;
using Transformable_Engine_v2.Engine.GameObjects.Containers;
using Transformable_Engine_v2.Engine.Graphics;
using Transformable_Engine_v2.Engine.Rendering;
using Transformable_Engine_v2.Engine.Transformable_Math.Geometry;

namespace Super_Management_Mayhem.GameRoot
{
    public class SuperManagementMayhem : Container
    {
        public enum PlayState
        {
            SelectCharacters,
            Playing,
            Results,
        }

        private const float VIEW_ZOOM = 2;
        private readonly GameMode.GameModes _mode;
        private readonly SelectPlayers.PlayerCount _players;
        private readonly int _teamCount;
        private PlayState _currentState;

        private MainMenu[] _menu;

        private Container _playScreenContainer;

        private Playscreen _playscreen;

        public SuperManagementMayhem(SelectPlayers.PlayerCount players,
                                     GameMode.GameModes gameMode,
                                     int teamCount)
        {
            _players = players;
            _mode = gameMode;

            _teamCount = teamCount;
        }

        public static TE_Vector2[] HudPosition { get; private set; }
        public static TE_Vector2 HudSize { get; private set; }

        public static TE_Vector2 HalfViewSize { get; private set; }

        public static int PlayerCount { get; private set; }

        public override void LoadContent()
        {
            base.LoadContent();

            CreateMainMenu(_mode, _teamCount);
        }

        private void OnPlayerReady()
        {
            if (_menu.All(m => m.IsReady))
            {
                IEnumerable<ProfileData> players = _menu.Select(x => x.Profile);

                CallMethod(3000, () => CreatePlayscreen(players.ToList()));
            }
        }

        private void ChangeState(PlayState nextState)
        {
            _currentState = nextState;
        }

        private void CreateMainMenu(GameMode.GameModes mode, int teamCount)
        {
            SpriteSheet.UnloadContent();

            MenuSheet.LoadContent();
            BorderSheet.LoadContent();
            ProfileIconSheet.LoadContent();
            ManagerSheet.LoadContent();

            CalculateHudSizeAndPosition();
            AddPlayerViews("viewMenu", 1);

            AddChildren(new Innerborder(_players, HudSize));

            _playScreenContainer = new Container();
            AddChildren(_playScreenContainer);

            _menu = new MainMenu[PlayerCount];
            for (int i = 0; i < _menu.Count(); i++)
            {
                _menu[i] = new MainMenu(i + 1, mode, teamCount);
                _menu[i].OnReady += OnPlayerReady;
            }
            AddChildren(_menu);

            AddChildren(new OuterBorder());

            ChangeState(PlayState.SelectCharacters);
        }

        private void CreateResultScreen(IEnumerable<ProfileData> profiles, int[] scores)
        {
            ClearChildren();

            _playscreen = null;
            BorderSheet.LoadContent();
            ResultSheet.LoadContent();
            ManagerSheet.LoadContent();
            MenuSheet.LoadContent();

            var teams = profiles.GroupBy(p => p.Team).Select(p => new TeamResult(p.First().Team.GetColor(), p.First().Team.Name, p.Select(x => new PlayerResult(x, scores[x.Id - 1])).ToArray())).ToList();

            AddChildren(new ResultScreen(teams));
            AddChildren(new OuterBorder());
            AddChildren(new FadeToBlack(Screens.FadeToBlack.Type.FadeFromBlack, 0, 1000));

            ChangeState(PlayState.SelectCharacters);
        }

        private void CreatePlayscreen(IEnumerable<ProfileData> players)
        {
            SelectTeamsMenu.Die();

            foreach (MainMenu menu in _menu)
            {
                menu.OnReady -= OnPlayerReady;
                menu.EndWaiting();
                menu.Die(3000);
            }

            AddPlayerViews("viewPlayer", VIEW_ZOOM);

            IEnumerable<PlayerDefinition> playerDefinitions = players.Select(p => new PlayerDefinition
                                                                                      {
                                                                                          Team = p.Team,
                                                                                          Id = p.Id,
                                                                                          Input =
                                                                                              InputKeys.FromFile(
                                                                                                  "Content/Config/Input/Player" +
                                                                                                  p.Id + ".input"),
                                                                                          Name = p.Name,
                                                                                      });

            _playscreen = new Playscreen(Playscreen.MapType.Castle,
                                         _mode,
                                         PlayerCount,
                                         playerDefinitions.ToList()
                );
            _playscreen.OnEndGame += i => CreateResultScreen(players.ToArray(), i);
            _playscreen.OnFadeToBlack += FadeToBlack;

            _playScreenContainer.AddChildren(_playscreen);

            ChangeState(PlayState.Playing);
        }

        private void CalculateHudSizeAndPosition()
        {
            switch (_players)
            {
                case SelectPlayers.PlayerCount.One:
                    HudSize = new TE_Vector2(Game.Options.ScreenSize.X - 4, Game.Options.ScreenSize.Y - 4);
                    HudPosition = new[]
                                      {
                                          new TE_Vector2(2, 2),
                                      };
                    PlayerCount = 1;
                    break;
                case SelectPlayers.PlayerCount.Two:
                    HudSize = new TE_Vector2((Game.Options.ScreenSize.X - 5)/2, (Game.Options.ScreenSize.Y - 4));
                    HudPosition = new[]
                                      {
                                          new TE_Vector2(2, 2),
                                          new TE_Vector2(3 + HudSize.X, 2)
                                      };
                    PlayerCount = 2;
                    break;
                case SelectPlayers.PlayerCount.Three:
                    HudSize = new TE_Vector2((Game.Options.ScreenSize.X - 6)/3, (Game.Options.ScreenSize.Y - 4));
                    HudPosition = new[]
                                      {
                                          new TE_Vector2(2, 2),
                                          new TE_Vector2(3 + HudSize.X, 2),
                                          new TE_Vector2(4 + HudSize.X*2, 2)
                                      };
                    PlayerCount = 3;
                    break;
                case SelectPlayers.PlayerCount.Four:
                    HudSize = new TE_Vector2((Game.Options.ScreenSize.X - 5)/2, (Game.Options.ScreenSize.Y - 5)/2);
                    HudPosition = new[]
                                      {
                                          new TE_Vector2(2, 2),
                                          new TE_Vector2(3 + HudSize.X, 2),
                                          new TE_Vector2(2, 3 + HudSize.Y),
                                          new TE_Vector2(3 + HudSize.X, 3 + HudSize.Y),
                                      };
                    PlayerCount = 4;
                    break;
                case SelectPlayers.PlayerCount.Six:
                    HudSize = new TE_Vector2((Game.Options.ScreenSize.X - 6)/3, (Game.Options.ScreenSize.Y - 5)/2);
                    HudPosition = new[]
                                      {
                                          new TE_Vector2(2, 2),
                                          new TE_Vector2(3 + HudSize.X, 2),
                                          new TE_Vector2(4 + HudSize.X*2, 2),
                                          new TE_Vector2(2, 3 + HudSize.Y),
                                          new TE_Vector2(3 + HudSize.X, 3 + HudSize.Y),
                                          new TE_Vector2(4 + HudSize.X*2, 3 + HudSize.Y)
                                      };
                    PlayerCount = 6;
                    break;
                case SelectPlayers.PlayerCount.Eight:
                    HudSize = new TE_Vector2((Game.Options.ScreenSize.X - 7)/4, (Game.Options.ScreenSize.Y - 5)/2);
                    HudPosition = new[]
                                      {
                                          new TE_Vector2(2, 2),
                                          new TE_Vector2(3 + HudSize.X, 2),
                                          new TE_Vector2(4 + HudSize.X*2, 2),
                                          new TE_Vector2(5 + HudSize.X*3, 2),
                                          new TE_Vector2(2, 3 + HudSize.Y),
                                          new TE_Vector2(3 + HudSize.X, 3 + HudSize.Y),
                                          new TE_Vector2(4 + HudSize.X*2, 3 + HudSize.Y),
                                          new TE_Vector2(5 + HudSize.X*3, 3 + HudSize.Y),
                                      };
                    PlayerCount = 8;
                    break;
            }

            HalfViewSize = (0.5f/VIEW_ZOOM)*new TE_Vector2(HudSize).ToGridbound();
        }

        private void AddPlayerViews(string name, float zoom)
        {
            for (int i = 0; i < PlayerCount; i++)
            {
                AddView(name + (i + 1), zoom, new TE_Rectangle(HudPosition[i], HudSize));
            }
        }

        private void AddView(string viewName,
                             float zoom,
                             TE_Rectangle viewArea)
        {
            ViewHandler.AddView(viewName, new TE_Rectangle(0, 0, zoom, zoom),
                                new TE_Rectangle(viewArea.X/Game.Options.ScreenSize.X,
                                                 viewArea.Y/Game.Options.ScreenSize.Y,
                                                 viewArea.Width/Game.Options.ScreenSize.X,
                                                 viewArea.Height/Game.Options.ScreenSize.Y));
        }

        public override void FixedStepUpdate(TimeSpan gameTime)
        {
            switch (_currentState)
            {
                case PlayState.SelectCharacters:
                    SelectTeamsMenu.SingleFixedStepUpdate(gameTime);
                    break;
            }

            base.FixedStepUpdate(gameTime);
        }

        public void FadeToBlack()
        {
            AddChildren(new FadeToBlack(Screens.FadeToBlack.Type.FadeToBlack, 2000, 1000));
        }
    }
}